package com.atguigu.guli.service.trade.controller.api;

import com.atguigu.guli.common.util.HttpClientUtils;
import com.atguigu.guli.common.util.StreamUtils;
import com.atguigu.guli.service.base.exception.GuliException;
import com.atguigu.guli.service.base.result.R;
import com.atguigu.guli.service.base.result.ResultCodeEnum;
import com.atguigu.guli.service.trade.entity.Order;
import com.atguigu.guli.service.trade.service.OrderService;
import com.atguigu.guli.service.trade.service.WeixinPayService;
import com.atguigu.guli.service.trade.util.WeixinPayProperties;
import com.github.wxpay.sdk.WXPayUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

//@CrossOrigin
@RestController
@RequestMapping("/api/trade/weixin-pay")
@Api(tags = "网站微信支付")
@Slf4j
public class ApiWeixinPayController {

    @Autowired
    private WeixinPayService weixinPayService;

    @Autowired
    private WeixinPayProperties weixinPayProperties;

    @Autowired
    private OrderService orderService;

    @ApiOperation("生成支付二维码")
    @GetMapping("create-native/{orderNo}")
    public R createNative(@PathVariable String orderNo, HttpServletRequest request){

        String remoteAddr = request.getRemoteAddr();
        Map<String, Object> map = weixinPayService.createNative(orderNo, remoteAddr);
        return R.ok().data(map);
    }

    /**
     * 支付回调：注意这里ja;lkfjklaf;klafkl;mnmm
     */
    @PostMapping("callback/notify")
    public String wxNotify(HttpServletRequest request) {

        try {
            System.out.println("微信回调方法被调用！");
            ServletInputStream inputStream = request.getInputStream();
            String notifyXml = StreamUtils.inputStream2String(inputStream, "utf-8");

            System.out.println("notifyXml：" + notifyXml);

            //验签
            boolean valid = WXPayUtil.isSignatureValid(notifyXml, weixinPayProperties.getPartnerKey());
            if(valid){
                System.out.println("验签成功！");

                //将字符串请求参数解析成map集合
                Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyXml);
                //String sign = notifyMap.get("sign");
                //boolean valid = WXPayUtil.isSignatureValid(notifyMap, weixinPayProperties.getPartnerKey());

                if("SUCCESS".equals(notifyMap.get("return_code")) && "SUCCESS".equals(notifyMap.get("result_code"))){

                    //验证金额的一致性
                    String totalFee = notifyMap.get("total_fee");
                    String tradeNo = notifyMap.get("out_trade_no");
                    Order order = orderService.getOrderByOrderNo(tradeNo);
                    if(order != null && order.getTotalFee().longValue() == Long.parseLong(totalFee)){

                        //要采用数据锁进行并发控制，以避免函数重入造成的数据混乱。
                        synchronized (this){
                            //处理重复通知（确保接口调用的幂等性）
                            //幂等性：接口远程调用的过程中，无论执行多少次重复的调用，结果都一致
                            if(order.getStatus() == 0){
                                //修改订单状态
                                orderService.updateOrderStatus(notifyMap);
                            }
                        }

                        HashMap<String, String> returnMap = new HashMap<>();
                        returnMap.put("return_code", "SUCCESS");
                        returnMap.put("return_msg", "OK");
                        String returnXml = WXPayUtil.mapToXml(returnMap);
                        return returnXml;
                    } else {
                        //告警通知
                        //记录日志，为系统管理员发送短信、站内信
                        log.error("金额不一致，告警通知！");
                    }
                }
            }else {
                //告警通知
                //记录日志，为系统管理员发送短信、站内信
                log.error("验签失败，告警通知！");
            }

            HashMap<String, String> returnMap = new HashMap<>();
            returnMap.put("return_code", "FAIL");
            returnMap.put("return_msg", "ERROR");
            String returnXml = WXPayUtil.mapToXml(returnMap);
            return returnXml;

        } catch (Exception e) {
            throw new GuliException(ResultCodeEnum.CALLBACK_ERROR);
        }
    }

    //获取沙箱密钥
    @GetMapping("get-sign-key")
    public R getSingKey() throws Exception {
        //获取验签秘钥API
        HttpClientUtils clientUtils = new HttpClientUtils("https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey");

        //组装接口参数
        HashMap<String, String> params = new HashMap<>();
        params.put("mch_id",weixinPayProperties.getPartner());//商户号
        params.put("nonce_str",WXPayUtil.generateNonceStr()); //生成随机字符串

        //将签名附加到参数列表中并转换成xml
        String xmlParams = WXPayUtil.generateSignedXml(params, weixinPayProperties.getPartnerKey());
        clientUtils.setXmlParam(xmlParams);//将参数放入请求对象的方法体
        clientUtils.setHttps(true);//使用https形式发送
        clientUtils.post();//发送请求
        String resultXml = clientUtils.getContent();//得到响应结果
        return R.ok().data("resultXml", resultXml);
    }
}
